/*
 * ArithmeticParser.h
 *
 *  Created on: 27.05.2012
 *      Author: ignacio
 */

#ifndef ARITHMETICPARSER_H_
#define ARITHMETICPARSER_H_

#include <vector>
using std::vector;
#include <list>
using std::list;
#include <iostream>
using std::ostream;
#include <string>
using std::string;
#include <sstream>
using std::ostringstream;

namespace neurignacio{

class Node;


class VirtualOperator
{
public:
	virtual ~VirtualOperator() {}
	virtual int operator()(Node* x, Node* y)=0;
	virtual string symbol() {return "?";}
	friend ostream& operator<<(ostream& out, VirtualOperator& op) {out << op.symbol(); return out;}
};

class Addition : public VirtualOperator
{
public:
	int operator()(Node* x, Node* y);
	virtual string symbol() {return "+";}
	friend ostream& operator<<(ostream& out, Addition& op)  {out << op.symbol(); return out;}
};

class Multiplication : public VirtualOperator
{
public:
	int operator()(Node* x, Node* y);
	virtual string symbol() {return "*";}
	friend ostream& operator<<(ostream& out, Multiplication& op)  {out << op.symbol(); return out;}
};

class Substraction : public VirtualOperator
{
public:
	int operator()(Node* x, Node* y);
	virtual string symbol() {return "-";}
	friend ostream& operator<<(ostream& out, Substraction& op)  {out << op.symbol(); return out;}
};

class Division : public VirtualOperator
{
public:
	int operator()(Node* x, Node* y);
	virtual string symbol() {return "/";}
	friend ostream& operator<<(ostream& out, Division& op)  {out << op.symbol(); return out;}
};

typedef VirtualOperator* OperatorPointer;

class Node
{
public:
	Node* left; // left child
	Node* right; // right child
	Node* p; // parent
public:
	Node() : left(0), right(0), p(0){}
	Node(Node* l, Node* r) : left(l), right(r), p(0) {}
	virtual ~Node() {}
	virtual int eval() const {return 0;}
	virtual string info() const {return "Node";}
	virtual string print();
	virtual size_t size() {return 0;}
	friend ostream& operator<<(ostream& out, Node& z) {out << z.info(); return out;}
};

class OperatorNode : public Node
{
public:
	OperatorPointer operation;
public:
	OperatorNode() : Node(), operation(0) {}
	OperatorNode(OperatorPointer op, Node* l=0, Node* r=0) : Node(l,r), operation(op) {}
	int eval() const {return (*operation)(left, right);}
	bool operator==(const OperatorNode& op) const {return (this->left==op.left && this->right==op.right && this->p==op.p && this->operation==op.operation);}
	virtual string info() const {return operation->symbol();}
	virtual string print();
	virtual size_t size() {return left->size()+right->size()+1;}
	friend ostream& operator<<(ostream& out, OperatorNode& z) {out << z.info(); return out;}
};

typedef int* NumberPointer;

class NumberNode: public Node
{
public:
	NumberPointer number;
public:
	NumberNode() : Node(), number(0) {}
	NumberNode(NumberPointer n, Node* l=0, Node* r=0) : Node(l,r), number(n) {}
	int eval() const {return *number;}
	bool operator==(const NumberNode& num) const {return (this->left==num.left && this->right==num.right && this->p==num.p && this->number==num.number);}
	virtual string info() const {ostringstream oss; oss << *number; return oss.str();}
	virtual string print();
	virtual size_t size() {return left->size()+right->size()+1;}
	friend ostream& operator<<(ostream& out, NumberNode& z) {out << z.info(); return out;}
};

class Tree
{
protected:
	static const int SENTINEL_KEY = -1;
	static const int NIL = 0;
	static Node SENTINEL;
	enum Child {NONE, LEFT, RIGHT};
public:
	static Node* nil;
	Node* root;
public:
	Tree();
	~Tree();
	void inorderTreeWalk(Node* x) const;
	void print() const {inorderTreeWalk(this->root);}
	size_t size() {return root->size();}
};

double fitScore(int value, int goal);

} // end namespace neurignacio
#endif /* ARITHMETICPARSER_H_ */

